/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package microlensing;

import algorithm.AlgorithmErrorException;
import algorithm.Encoder;
import algorithm.Genotype;
import algorithm.Phenotype;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javalens.astronomy.Event;
import simple.BitStringGenotype;
import simple.DoubleArrayBitStringEncoder;
import simple.DoubleArrayPhenotype;

/**
 *
 * @author vermaak
 */
public class MicrolensEventBitStringEncoder implements Encoder {

    final private Event min;
    final private Event max;
    final private Event start;
    final private List<String> toFit;
    private transient DoubleArrayBitStringEncoder baseEncoder;

    public MicrolensEventBitStringEncoder(Event min, Event max, Event start, List<String> toFit, int bitsPerValue, int nDoubleValues) {
        this.min = min;
        this.max = max;
        this.start = start;
        this.toFit = toFit;

        this.baseEncoder = new DoubleArrayBitStringEncoder(bitsPerValue, nDoubleValues);
    }

    @Override
    public Phenotype toPhenoType(Genotype genotype) throws AlgorithmErrorException {
        // first map bitstring to doubles
        double[] values = ((DoubleArrayPhenotype) baseEncoder.toPhenoType(genotype)).getValues();
        // then map doubles to a microlensing event
        Event evt;
        try {
            evt = (Event) start.clone();
        } catch (CloneNotSupportedException ex) {
            throw new AlgorithmErrorException("Could not clone Microlensing event.");
        }
        for (int i = 0; i < values.length; ++i) {
            String name = toFit.get(i);
            if (name.equals("a")) {
                evt.setA(values[i] * (max.getA() - min.getA()) + min.getA());
            }
            if (name.equals("ang")) {
                evt.setAng(values[i] * (max.getAng() - min.getAng()) + min.getAng());
            }
            if (name.equals("b")) {
                evt.setB(values[i] * (max.getB() - min.getB()) + min.getB());
            }
            if (name.equals("f")) {
                evt.setF(values[i] * (max.getF() - min.getF()) + min.getF());
            }
            if (name.equals("m0")) {
                evt.setM0(values[i] * (max.getM0() - min.getM0()) + min.getM0());
            }
            if (name.equals("psi")) {
                evt.setPsi(values[i] * (max.getPsi() - min.getPsi()) + min.getPsi());
            }
            if (name.equals("q")) {
                evt.setQ(values[i] * (max.getQ() - min.getQ()) + min.getQ());
            }
            if (name.equals("rho")) {
                evt.setRho(values[i] * (max.getRho() - min.getRho()) + min.getRho());
            }
            if (name.equals("rs")) {
                evt.setRs(values[i] * (max.getRs() - min.getRs()) + min.getRs());
            }
            if (name.equals("te")) {
                evt.setTe(values[i] * (max.getTe() - min.getTe()) + min.getTe());
            }
            if (name.equals("tm")) {
                evt.setTm(values[i] * (max.getTm() - min.getTm()) + min.getTm());
            }
        }
        return new MicrolensEventPhenotype(evt);
    }

    @Override
    public Genotype toGenoType(Phenotype phenotype) throws AlgorithmErrorException {
        if (!(phenotype instanceof MicrolensEventPhenotype)) {
            throw new AlgorithmErrorException("Requires a MicrolensingEventPhenotype.");
        }
        // map Microlensing event to doubles
        double[] values = new double[toFit.size()];
        for (int i = 0; i < toFit.size(); ++i) {
            String name = toFit.get(i);
            Event evt = ((MicrolensEventPhenotype) phenotype).getEvent();
            if (name.equals("a")) {
                values[i] = (evt.getA() - min.getA()) / (max.getA() - min.getA());
            }
            if (name.equals("ang")) {
                values[i] = (evt.getAng() - min.getAng()) / (max.getAng() - min.getAng());
            }
            if (name.equals("b")) {
                values[i] = (evt.getB() - min.getB()) / (max.getB() - min.getB());
            }
            if (name.equals("f")) {
                values[i] = (evt.getF() - min.getF()) / (max.getF() - min.getF());
            }
            if (name.equals("m0")) {
                values[i] = (evt.getM0() - min.getM0()) / (max.getM0() - min.getM0());
            }
            if (name.equals("psi")) {
                values[i] = (evt.getPsi() - min.getPsi()) / (max.getPsi() - min.getPsi());
            }
            if (name.equals("q")) {
                values[i] = (evt.getQ() - min.getQ()) / (max.getQ() - min.getQ());
            }
            if (name.equals("rho")) {
                values[i] = (evt.getRho() - min.getRho()) / (max.getRho() - min.getRho());
            }
            if (name.equals("rs")) {
                values[i] = (evt.getRs() - min.getRs()) / (max.getRs() - min.getRs());
            }
            if (name.equals("te")) {
                values[i] = (evt.getTe() - min.getTe()) / (max.getTe() - min.getTe());
            }
            if (name.equals("tm")) {
                values[i] = (evt.getTm() - min.getTm()) / (max.getTm() - min.getTm());
            }
        }
        // map doubles to bits
        return baseEncoder.toGenoType(new DoubleArrayPhenotype(values));
    }
}
